/**
 * @file value.cpp
 * @brief VimL虚拟机值类型实现
 * @author VimLVM Team
 * @date 2025
 */

#include "viml/value.h"
#include <sstream>

namespace viml {

ValueType Value::type() const {
    switch (data_.index()) {
        case 0: return ValueType::NIL;
        case 1: return ValueType::BOOLEAN;
        case 2: return ValueType::NUMBER;
        case 3: return ValueType::STRING;
        case 4: return ValueType::LIST;
        case 5: return ValueType::DICT;
        case 6: return ValueType::FUNCTION;
        case 7: return ValueType::CLOSURE;
        default: return ValueType::NIL;
    }
}

bool Value::is_nil() const { return type() == ValueType::NIL; }
bool Value::is_boolean() const { return type() == ValueType::BOOLEAN; }
bool Value::is_number() const { return type() == ValueType::NUMBER; }
bool Value::is_string() const { return type() == ValueType::STRING; }
bool Value::is_list() const { return type() == ValueType::LIST; }
bool Value::is_dict() const { return type() == ValueType::DICT; }
bool Value::is_function() const { return type() == ValueType::FUNCTION; }
bool Value::is_closure() const { return type() == ValueType::CLOSURE; }

bool Value::as_boolean() const {
    if (!is_boolean()) return false;
    return std::get<bool>(data_);
}

double Value::as_number() const {
    if (!is_number()) return 0.0;
    return std::get<double>(data_);
}

const std::string& Value::as_string() const {
    static const std::string empty;
    if (!is_string()) return empty;
    return std::get<std::string>(data_);
}

const std::shared_ptr<List>& Value::as_list() const {
    static const std::shared_ptr<List> empty;
    if (!is_list()) return empty;
    return std::get<std::shared_ptr<List>>(data_);
}

const std::shared_ptr<Dict>& Value::as_dict() const {
    static const std::shared_ptr<Dict> empty;
    if (!is_dict()) return empty;
    return std::get<std::shared_ptr<Dict>>(data_);
}

const std::shared_ptr<Function>& Value::as_function() const {
    static const std::shared_ptr<Function> empty;
    if (!is_function()) return empty;
    return std::get<std::shared_ptr<Function>>(data_);
}

const std::shared_ptr<Closure>& Value::as_closure() const {
    static const std::shared_ptr<Closure> empty;
    if (!is_closure()) return empty;
    return std::get<std::shared_ptr<Closure>>(data_);
}

std::string Value::to_string() const {
    std::ostringstream oss;
    
    switch (type()) {
        case ValueType::NIL:
            oss << "nil";
            break;
        case ValueType::BOOLEAN:
            oss << (as_boolean() ? "true" : "false");
            break;
        case ValueType::NUMBER:
            oss << as_number();
            break;
        case ValueType::STRING:
            oss << '"' << std::get<std::string>(data_) << '"';
            break;
        case ValueType::LIST: {
            const auto& list = as_list()->elements;
            oss << "[";
            for (size_t i = 0; i < list.size(); ++i) {
                if (i > 0) oss << ", ";
                oss << list[i]->to_string();
            }
            oss << "]";
            break;
        }
        case ValueType::DICT: {
            const auto& dict = as_dict()->elements;
            oss << "{";
            bool first = true;
            for (const auto& [key, value] : dict) {
                if (!first) oss << ", ";
                oss << key << ": " << value->to_string();
                first = false;
            }
            oss << "}";
            break;
        }
        case ValueType::FUNCTION:
            oss << "<function " << as_function()->name << ">";
            break;
        case ValueType::CLOSURE:
            oss << "<closure " << as_closure()->function->name << ">";
            break;
    }
    
    return oss.str();
}

bool Value::operator==(const Value& other) const {
    if (type() != other.type()) return false;
    
    switch (type()) {
        case ValueType::NIL:
            return true;
        case ValueType::BOOLEAN:
            return as_boolean() == other.as_boolean();
        case ValueType::NUMBER:
            return as_number() == other.as_number();
        case ValueType::STRING:
            return as_string() == other.as_string();
        case ValueType::LIST:
            return as_list() == other.as_list();
        case ValueType::DICT:
            return as_dict() == other.as_dict();
        case ValueType::FUNCTION:
            return as_function() == other.as_function();
        case ValueType::CLOSURE:
            return as_closure() == other.as_closure();
    }
    
    return false;
}

bool Value::operator!=(const Value& other) const {
    return !(*this == other);
}

} // namespace viml